/*
 * tc.c
 *
 * Created: 04/02/2014 21:11:48
 *  Author: usuario
 */ 

#include <asf.h>
#include "pulses.h"

#define TC_CAPTURE_TIMER_SELECTION TC_CMR_TCCLKS_TIMER_CLOCK2

static const uint32_t divisors[5] = { 2, 8, 32, 128, 0};

static uint32_t gs_ul_captured_pulses;
static uint64_t gs_ul_captured_ra;
static uint64_t gs_ul_captured_rb;

static pulses_t *pulses_target_buffer;
static pulses_t pulses;
static int get_pulses;

xSemaphoreHandle xSemaphore_pulses_mutex = NULL;
xSemaphoreHandle xSemaphore_pulses_notification = NULL;

void PULSES_setup ( void )
{
	
	ioport_set_pin_mode(PIN_TC_CAPTURE, PIN_TC_CAPTURE_MUX);
	/* Disable IO to enable peripheral mode) */
	ioport_disable_pin(PIN_TC_CAPTURE);
		
	/* Configure the PMC to enable the TC module */
	sysclk_enable_peripheral_clock(ID_TC_CAPTURE);

	/* Init TC to capture mode. */
	tc_init(TC, TC_CHANNEL_CAPTURE,
	TC_CAPTURE_TIMER_SELECTION /* Clock Selection */
	| TC_CMR_LDRA_FALLING /* RA Loading: falling edge of TIOA */
	| TC_CMR_LDRB_RISING  /* RB Loading: rising edge of TIOA */
	| TC_CMR_ABETRG /* External Trigger: TIOA */
	| TC_CMR_ETRGEDG_RISING /* External Trigger Edge: Falling edge */
	);
	
	xSemaphore_pulses_mutex = xSemaphoreCreateMutex();
	configASSERT(xSemaphore_pulses_mutex);
		
	get_pulses=0;
	
	tc_enable_interrupt(TC, TC_CHANNEL_CAPTURE, TC_IER_LDRBS);
	tc_start(TC, TC_CHANNEL_CAPTURE);
	
	NVIC_DisableIRQ(TC_IRQn);
	NVIC_ClearPendingIRQ(TC_IRQn);
	NVIC_SetPriority(TC_IRQn, PULSE_IRQ_PRIORITY);
	NVIC_EnableIRQ(TC_IRQn);
}

void TC_Handler(void)
{
	portBASE_TYPE higher_priority_task_woken = pdFALSE;
	
	if ((tc_get_status(TC, TC_CHANNEL_CAPTURE) & TC_SR_LDRBS) == TC_SR_LDRBS) {
		//taskENTER_CRITICAL();
		gs_ul_captured_ra = tc_read_ra(TC, TC_CHANNEL_CAPTURE);
		gs_ul_captured_rb = tc_read_rb(TC, TC_CHANNEL_CAPTURE);
		//taskEXIT_CRITICAL();
		
		pulses[gs_ul_captured_pulses].up =   1000000 * gs_ul_captured_ra / ((sysclk_get_peripheral_bus_hz(TC) /	divisors[TC_CAPTURE_TIMER_SELECTION]));
		pulses[gs_ul_captured_pulses].down = 1000000 * (gs_ul_captured_rb - gs_ul_captured_ra) / ((sysclk_get_peripheral_bus_hz(TC) /	divisors[TC_CAPTURE_TIMER_SELECTION]));
		
		
		gs_ul_captured_pulses++;
		
		if (gs_ul_captured_pulses >= PULSES_NUM_PULSES)
		{
			gs_ul_captured_pulses=0;
			if (get_pulses == 1)
			{
				get_pulses=0;
				memcpy(pulses_target_buffer , pulses, sizeof(pulses));
				if (xSemaphore_pulses_notification!=NULL)
					xSemaphoreGiveFromISR(xSemaphore_pulses_notification, &higher_priority_task_woken);
				xSemaphoreGiveFromISR(xSemaphore_pulses_mutex, &higher_priority_task_woken);
			}
		}
	}
	
	portEND_SWITCHING_ISR(higher_priority_task_woken);
}

void PULSES_get_pulses(pulses_t *ptr_pulses, portTickType block_time_ticks, xSemaphoreHandle notification_semaphore)
{	
	xSemaphoreTake(xSemaphore_pulses_mutex, block_time_ticks);
	
	taskENTER_CRITICAL();
	pulses_target_buffer=ptr_pulses;
	get_pulses=1;
	taskEXIT_CRITICAL();
	
	xSemaphore_pulses_notification=notification_semaphore;
	if (xSemaphore_pulses_notification!=NULL)
		xSemaphoreTake(xSemaphore_pulses_notification, block_time_ticks);
}
